package client

import (
	"net"
	"sync"

	"github.com/spf13/cobra"
	"go.uber.org/zap"

	"go-war3proxy/pkg/const"
)

// Client War3代理客户端
type Client struct {
	connectionMap    map[string]*War3Server
	logger           *zap.Logger
	mutex            sync.RWMutex
	serverIP         string
	serverPort       int
	war3LocalIP      net.IP
	connectionServer *ConnectionWar3ProxyServer
	broadcast        *LocalWar3GameBroadcast
}

// ClientConfig 客户端配置
type ClientConfig struct {
	ServerIP   string
	ServerPort int
}

// NewClient 创建新的客户端实例
func NewClient(config ClientConfig, logger *zap.Logger) (*Client, error) {
	// 获取本地IP地址
	localIP, err := getLocalIP()
	if err != nil {
		return nil, err
	}

	if config.ServerIP == "" {
		config.ServerIP = consts.DefaultClientServerIP
	}
	if config.ServerPort == 0 {
		config.ServerPort = consts.DefaultServerPort
	}

	client := &Client{
		connectionMap: make(map[string]*War3Server),
		logger:        logger.With(zap.String("component", "client")),
		serverIP:      config.ServerIP,
		serverPort:    config.ServerPort,
		war3LocalIP:   localIP,
	}

	// 初始化连接服务器和广播组件
	client.connectionServer = NewConnectionWar3ProxyServer(client, logger)
	client.broadcast = NewLocalWar3GameBroadcast(client, logger)

	return client, nil
}

// Start 启动客户端
func (c *Client) Start() error {
	c.logger.Info("启动客户端",
		zap.String("server_ip", c.serverIP),
		zap.Int("server_port", c.serverPort),
		zap.String("local_ip", c.war3LocalIP.String()))

	// 启动连接服务器
	go c.connectionServer.Start()

	// 启动本地广播监听
	return c.broadcast.Start()
}

// Stop 停止客户端
func (c *Client) Stop() {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	// 关闭所有War3Server
	for _, war3Server := range c.connectionMap {
		war3Server.Close()
	}
	c.connectionMap = make(map[string]*War3Server)

	c.logger.Info("客户端已停止")
}

// GetConnectionServer 获取连接服务器
func (c *Client) GetConnectionServer() *ConnectionWar3ProxyServer {
	return c.connectionServer
}

// AddWar3Server 添加War3Server
func (c *Client) AddWar3Server(otherWar3IP string, war3Server *War3Server) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	// 如果已存在，先关闭旧的
	if oldWar3Server, exists := c.connectionMap[otherWar3IP]; exists {
		c.logger.Warn("War3Server已存在，关闭旧的", zap.String("other_war3_ip", otherWar3IP))
		oldWar3Server.Close()
	}

	c.connectionMap[otherWar3IP] = war3Server
	c.logger.Info("添加War3Server", zap.String("other_war3_ip", otherWar3IP))
}

// RemoveWar3Server 移除War3Server
func (c *Client) RemoveWar3Server(otherWar3IP string) {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	if war3Server, exists := c.connectionMap[otherWar3IP]; exists {
		war3Server.Close()
		delete(c.connectionMap, otherWar3IP)
		c.logger.Info("移除War3Server", zap.String("other_war3_ip", otherWar3IP))
	}
}

// GetWar3Server 获取War3Server
func (c *Client) GetWar3Server(otherWar3IP string) *War3Server {
	c.mutex.RLock()
	defer c.mutex.RUnlock()
	return c.connectionMap[otherWar3IP]
}

// GetAllWar3Servers 获取所有War3Server
func (c *Client) GetAllWar3Servers() map[string]*War3Server {
	c.mutex.RLock()
	defer c.mutex.RUnlock()

	result := make(map[string]*War3Server)
	for k, v := range c.connectionMap {
		result[k] = v
	}
	return result
}

// GetServerIP 获取服务器IP
func (c *Client) GetServerIP() string {
	return c.serverIP
}

// GetServerPort 获取服务器端口
func (c *Client) GetServerPort() int {
	return c.serverPort
}

// GetWar3LocalIP 获取本地War3 IP
func (c *Client) GetWar3LocalIP() net.IP {
	return c.war3LocalIP
}

// getLocalIP 获取本地IP地址
func getLocalIP() (net.IP, error) {
	// 尝试获取本地主机名对应的IP地址
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return nil, err
	}

	// 遍历所有网络接口地址
	for _, addr := range addrs {
		if ipNet, ok := addr.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
			// 只返回IPv4地址
			if ipNet.IP.To4() != nil {
				return ipNet.IP, nil
			}
		}
	}

	// 如果上面的方法失败，使用UDP连接方式
	conn, err := net.Dial("udp", "8.8.8.8:80")
	if err != nil {
		return nil, err
	}
	defer conn.Close()

	localAddr := conn.LocalAddr().(*net.UDPAddr)
	return localAddr.IP, nil
}

// NewClientCommand 创建客户端命令
func NewClientCommand(logger *zap.Logger) *cobra.Command {
	var config ClientConfig

	cmd := &cobra.Command{
		Use:   "client",
		Short: "启动War3代理客户端",
		Long:  `启动War3代理客户端，连接到服务器并处理游戏数据转发`,
		RunE: func(cmd *cobra.Command, args []string) error {
			client, err := NewClient(config, logger)
			if err != nil {
				return err
			}
			return client.Start()
		},
	}

	cmd.Flags().StringVar(&config.ServerIP, "serverIp", "", "War3代理服务器IP地址 (默认: 192.168.56.1)")
	cmd.Flags().IntVar(&config.ServerPort, "serverPort", 0, "War3代理服务器端口 (默认: 9527)")

	return cmd
}
